//@author A0101200R

package logic;

import org.joda.time.DateTime;

import applogger.AppLogger;
import storage.ScheduleEvent;
import storage.Storage;

public class ScheduleDisplay {

	// list of command details
	private static final String EMPTY_STRING = "";
	private static final String TODAY = EMPTY_STRING;
	private static final String DONE = "done";
	private static final String UNDONE = "undone";
	private static final String ALL = "all";

	// list of error messages
	private static final String ERROR_NO_SCHEDULE = "Error! There is no tasks.";
	private static final String ERROR_WRONG_INPUT = "Error! The input after command is wrong.";
	private static final String ERROR_INVALID_INDEX = "Error! The index you want to display is invalid.";
	
	// list of messages
	private static final String MSG_RESULTS_NOT_FOUND = "No search results found. Please try again!";
	private static final String MSG_TODAY_NO_TASKS = "There are no tasks today.";
	private static final String MSG_EMPTY = "No tasks in this section.";
	private static final String MSG_LOG_NON_NUMERICAL_INPUT = "In display, there is a number format exception error.";
	
	// list of variables from other classes
	ScheduleSorter eventsSort;
	ScheduleSearcher eventsSearch;
	ScheduleEvent taskToDisplay;
	Storage eventsList;
	DateTime date;

	// constructor
	public ScheduleDisplay(Storage eventsList, ScheduleSorter eventsSort, ScheduleSearcher eventsSearch) {
		this.eventsList = eventsList;
		this.eventsSort = eventsSort;
		this.eventsSearch = eventsSearch;
		date = new DateTime();
	}

	/**
	 * Display a list of tasks according to user's request. 
	 * If it is an empty string, it will return the list of tasks on the particular day itself.
	 * If it is "all", it will return the entire list of tasks available in storage.
	 * If it is "done", it will return a list of tasks done.
	 * If it is "undone", it will return a list of tasks undone.
	 * If it is an index, it will return the details of the task of the index.
	 * If the list is empty, it will return an ERROR_NO_SCHEDULE message.
	 * 
	 * @param userCommandDetails
	 * @return ERROR_NO_SCHEDULE or eventsDetails
	 */

	public String displayEvents(String userCommandDetails) {
		assert userCommandDetails != null;
		
		int index = -1;
		boolean isNumber = true;
		
		try {
			index = Integer.parseInt(userCommandDetails);
		} catch (NumberFormatException e) {
			AppLogger.log(MSG_LOG_NON_NUMERICAL_INPUT);
			isNumber = false;
		}

		String eventsDetails = retrieveEvents(index, isNumber, userCommandDetails);

		if (eventsDetails.equals(EMPTY_STRING)) {
			return ERROR_NO_SCHEDULE;
		} else {
			return eventsDetails;
		}
	}
	
	/**
	 * Check if the input is a number or a string.
	 * If it is a number, we will retrieve details of the task of the number.
	 * If it is a string, we will retrieve a list of tasks according to the request 
	 * of the user.
	 * 
	 * @param index
	 * @param isNumber
	 * @param userCommandDetails
	 * @return eventsDetails
	 */
	protected String retrieveEvents(int index, boolean isNumber, String userCommandDetails) {
		String eventsDetails;
		int size = eventsList.getSize();
		
		if (isNumber) {
			eventsDetails = detailsOfIndexEvent(index, size);
		} else {
			eventsDetails = detailsOfStringEvent(userCommandDetails, size);
		}
				
		return eventsDetails;
	}
	
	/**
	 * Check and retrieve the details of task of the index.
	 * If the index typed by the user is invalid, it will return ERROR_INVALID_INDEX message.
	 * If the index is valid, it will return the details of task of the index.
	 * 
	 * @param index
	 * @param size
	 * @return ERROR_INVALID_INDEX or taskToDisplay.toString()
	 */
	protected String detailsOfIndexEvent(int index, int size) {
		if (index <= 0 || index > size) {
			return ERROR_INVALID_INDEX;
		}
		
		taskToDisplay = eventsList.getEvent(index - 1);
		return taskToDisplay.toString();
	}
	
	/**
	 * Check and retrieve list of tasks according to userCommandDetails.
	 * If the userCommandDetails is valid, it will retrieve details according to the input.
	 * If the userCommandDetails is invalid, it will return ERROR_WRONG_INPUT message.
	 * 
	 * @param userCommandDetails
	 * @param size
	 * @return ERROR_WRONG_INPUT or eventsDetails
	 */
	protected String detailsOfStringEvent(String userCommandDetails, int size) {
		String eventsDetails;

		switch (userCommandDetails) {
		
		case ALL:
			eventsDetails = allTasks(ALL, size);
			break;
		case TODAY:
			eventsDetails = todayTasks();
			break;
		case DONE:
			eventsDetails = doneOrUndoneTasks(size, DONE);
			break;
		case UNDONE:
			eventsDetails = doneOrUndoneTasks(size, UNDONE);
			break;
		default:
			return ERROR_WRONG_INPUT;	
		}
		return eventsDetails;
	}

	/**
	 * Retrieve all the available tasks in the list.
	 * If the size of list is less than or equal to 5, all the details will be shown.
	 * If the size of list is more than 5, only the name of the tasks will be shown.
	 * 
	 * @param userCommandDetails
	 * @param size
	 * @return eventsList.toString() or eventsList.toShortString()
	 */
	protected String allTasks(String userCommandDetails, int size) {
		eventsSort.sortEvents(userCommandDetails);

		if (size <= 5) {
			return eventsList.toString();
		} else {
			return eventsList.toShortString();
		}
	}
	
	/**
	 * Retrieve all the tasks that need to complete on the particular day.
	 * Search for the date to see if there is any tasks on that day.
	 * If no tasks, it will return MSG_TODAY_NO_TASKS message.
	 * 
	 * @return eventsDetails or MSG_TODAY_NO_TASKS
	 */
	protected String todayTasks() {
		String todayDate = date.toString("ddMMyyyy");
		String eventsDetails = eventsSearch.searchEventsByDate(todayDate);
		
		boolean noTasks = eventsDetails.equals(MSG_RESULTS_NOT_FOUND); 
		if (noTasks) {
			eventsDetails = MSG_TODAY_NO_TASKS;
		}
		
		return eventsDetails;
	}
	
	/**
	 * Retrieve a list of done or undone tasks.
	 * If the size of list is less than or equal to 5, all the details will be shown.
	 * If the size of list is more than 5, only the name of the tasks will be shown.
	 * If the list is empty, it will return MSG_EMPTY.
	 *  
	 * @param size
	 * @param command
	 * @return eventsDetails or MSG_EMPTY
	 */
	protected String doneOrUndoneTasks(int size, String command) {
		String eventsDetails;
		boolean done = command.equals(DONE);
		
		if (size <= 5) {
			eventsDetails = eventsList.doneString(done);
		} else {
			eventsDetails  = eventsList.doneShortString(done);
		}
		
		if (eventsDetails.equals(EMPTY_STRING)) {
			return MSG_EMPTY;
		}
		
		return eventsDetails;
	}
}
